
#include "codec/alaw_codec.h"
#include "logger.h"

unsigned char CAlawCodec::mExponentTable[128] = {
	0, 1, 2, 2, 3, 3, 3, 3,
	4, 4, 4, 4, 4, 4, 4, 4,
	5, 5, 5, 5, 5, 5, 5, 5,
	5, 5, 5, 5, 5, 5, 5, 5,
	6, 6, 6, 6, 6, 6, 6, 6,
	6, 6, 6, 6, 6, 6, 6, 6,
	6, 6, 6, 6, 6, 6, 6, 6,
	6, 6, 6, 6, 6, 6, 6, 6,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7
};


CAlawCodec::CAlawCodec()
{
}

CAlawCodec::~CAlawCodec()
{
}

NAudioFormats::ECodec CAlawCodec::getCodecType()
{
	return NAudioFormats::ALAW;
}

double CAlawCodec::convertFromS8ToDouble(int8_t pSample)
{
	return convertFromU8ToDouble(pSample);
}

int8_t CAlawCodec::convertFromDoubleToS8(double pSample)
{
	return convertFromDoubleToU8(pSample);
}

double CAlawCodec::convertFromU8ToDouble(uint8_t pSample)
{
	// xor with 01010101. MSB (signbit) will be unchanged.
	pSample ^= 0x55;

	bool lNegative(false);
	// check if negative
	if(pSample & 0x80) {
		lNegative = true;
		pSample &= 0x7F; // reset MSB (bit 8)
	}
	unsigned int lExponent = pSample >> 4;

	// reset bit 7 and 6, and set bit 5 (bit 1 is the LSB)
	// Doesn't set bit 5 if exponent is 0
	pSample &= 0x0F;
	if(lExponent) {
		pSample |= 0x10;
	}

	unsigned int lUncompressed(pSample << 1);
	lUncompressed |= 0x01; // set LSB to 1
	if(lExponent) {
		lUncompressed <<= (lExponent - 1);
	}

	// Now lUncompressed is a 12 bit value (4096, from 0 to 4095)
	// lowest: 000001b = 0x01 = 1;
	// highest: 111111000000b = 0x0FC0 = 4032
	double lValue = static_cast<double>(lUncompressed) / 4095.0;
	if(lNegative) {
		lValue *= -1.0;
	}
	return lValue;
}

uint8_t CAlawCodec::convertFromDoubleToU8(double pSample)
{
	if(pSample > 1.0) {
		printl(LL_WARN, __FILE__, "Sample > 1.0 (%lf)", pSample);
		pSample = 1.0;
	}
	if(pSample < -1.0) {
		printl(LL_WARN, __FILE__, "Sample < -1.0 (%lf)", pSample);
		pSample = -1.0;
	}
	bool lNegative(false);
	if(pSample < 0.0) {
		lNegative = true;
		pSample *= -1.0;
	}
	unsigned int lUncompressed(static_cast<unsigned int>(pSample * 4095.0 + 0.5));
	if(lUncompressed > 4095) {
		printl(LL_WARN, __FILE__, "%u > 4095 (sample: %lf)\n",
				lUncompressed,
				pSample);
		lUncompressed = 4095;
	}
	unsigned int lExponent = mExponentTable[lUncompressed >> 5];

	// store mantissa to lUncompressed (overwrite lUncompressed)
	lUncompressed >>= lExponent;
	if(lExponent == 0) {
		lUncompressed >>= 1;
	}
	lUncompressed &= 0x0F; // reset the fifth bit (which is set by exponent > 0)

	uint8_t lCompressed((lExponent << 4) + lUncompressed);
	if(lNegative) {
		lCompressed |= 0x80;
	}
	return lCompressed ^ 0x55;
}

double CAlawCodec::convertFromS16ToDouble(int16_t pSample)
{
	printl(LL_ERR, __FILE__, "Alaw doesn't support 16bit signed samples.\n");
	return 0.0;
}

int16_t CAlawCodec::convertFromDoubleToS16(double pSample)
{
	printl(LL_ERR, __FILE__, "Alaw can't create 16bit signed samples.\n");
	return 0;
}

double CAlawCodec::convertFromU16ToDouble(uint16_t pSample)
{
	printl(LL_ERR, __FILE__, "Alaw doesn't support 16bit unsigned samples.\n");
	return 0.0;
}

uint16_t CAlawCodec::convertFromDoubleToU16(double pSample)
{
	printl(LL_ERR, __FILE__, "Alaw can't create 16bit unsigned samples.\n");
	return 0;
}
